package pl.edu.mimuw.mas.agent;

import jade.core.AID;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import pl.edu.mimuw.mas.agent.behaviour.DFRegisterBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.DFUnregisterBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.hunting.DeerPositionServerBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.hunting.MoveBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.hunting.grouping.CharismaServerBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.hunting.grouping.LeaderServerBehaviour;
import pl.edu.mimuw.mas.util.GroupHelper;
import pl.edu.mimuw.mas.util.Position;
import pl.edu.mimuw.mas.util.PositionHelper;

public abstract class HuntingAgent extends AbstractAgent {

	private static final long serialVersionUID = 9190027117383106665L;
	
	public final static String HUNTING_SERVICE_TYPE = "hunting-service";
	public final static String LEADER_SERVICE_TYPE = "leader-service";
	
	public static final String DEER_POSITION_INFO_CONV = "deer-position-conv";
	public static final String CHARISMA_CONV = "charisma-conv";
	public static final String GROUP_CONV = "group-conv";
	
	protected Position deerPosition; // ostatnia znana pozycja losia
	protected long lastDeerPositionUpdate; // czas aktualizacji ostatniej pozycji łosia
	
	private double charisma;
	private HashMap<AID, Double> charismaCache;
	
	private AID leader;
	private boolean isLeader;
	private Set<AID> group;
	
	public HuntingAgent() {
		deerPosition = null;
		lastDeerPositionUpdate = 0;
		
		charisma = Math.random() * GroupHelper.groupingFactor;
		if (charisma == 0)
			charisma = GroupHelper.groupingFactor;
		charismaCache = new HashMap<AID, Double>();
		
		leader = null;
		isLeader = false;
		group = new HashSet<AID>();
	}
	
	protected void addHuntingBehaviour() {
		addBehaviour(new DFRegisterBehaviour(this, HUNTING_SERVICE_TYPE));
		addBehaviour(new MoveBehaviour(this));
		addBehaviour(new DeerPositionServerBehaviour(this));
		addBehaviour(new CharismaServerBehaviour(this));
		addBehaviour(new LeaderServerBehaviour(this));
	}
	
	public abstract void scare();
	
	public long getLastDeerPositionUpdate() {
		return lastDeerPositionUpdate;
	}

	public void setLastDeerPositionUpdate(long lastDeerPositionUpdate) {
		this.lastDeerPositionUpdate = lastDeerPositionUpdate;
	}
	
	public Position getDeerPosition() {
		return deerPosition;
	}
	
	public void setDeerPosition(Position p) {
		this.deerPosition = p;
	}

	public double getCharisma() {
		return charisma;
	}
	
	public double getEffectiveCharisma(Position p) {
		double a = getCharisma();
		float d = PositionHelper.getDistance(getPosition(), p);
		return 1 / ((d) + (1 / a));
	}
	
	public HashMap<AID, Double> getCharismaCache() {
		return charismaCache;
	}

	public AID getLeader() {
		return leader;
	}

	public void setLeader(AID leader) {
		if (!getAID().equals(leader)) { // naleze do czyjejs grupy
			this.leader = leader;
			if (isLeader) {
				addBehaviour(new DFUnregisterBehaviour(this, LEADER_SERVICE_TYPE));
			}
			isLeader = false;
		} else { // sam jestem liderem
			this.leader = null;
			if (!isLeader) {
				addBehaviour(new DFRegisterBehaviour(this, LEADER_SERVICE_TYPE));
			}
			isLeader = true;
		}
	}

	public boolean isLeader() {
		return isLeader;
	}

	public Set<AID> getGroup() {
		return group;
	}
	
	public Position getAvgGroupPosition() {
		if (!isLeader()) {
			return null; // informacje o grupie ma tylko lider
		}
		
		Position ret = new Position(getPosition().x, getPosition().y);
		int cnt = 1;
		
		Position p;
		for (AID aid : group) {
			p = PositionHelper.getPosition(this.getClass(), aid);
			ret.x += p.x;
			ret.y += p.y;
			cnt++;
		}
		ret.x /= cnt;
		ret.y /= cnt;
		
		return ret;
	}
	
	public String getServiceType() {
		return HuntingAgent.HUNTING_SERVICE_TYPE;
	}
	
	public abstract void activate();
	
}
